查看原文
其他

2年重写10年279万行代码……全文一字一字看完,真的感同身受

嵌入式ARM 2021-01-31
本文来自《华为人》,公众号心声社区,作者:刘文杰


改变,做最好的软件✚●○
刘文杰


2018年年底,华为网络金码奖颁奖典礼会场掌声雷动,看着台上我们团队的3名员工站立正中,举起象征着“码农”至高荣誉的奖杯,我在台下思绪万千。


两年前,公司5G微波等新产品启动开发,工作量几近翻倍,为提高开发效率和质量,我们一边顶着巨大的交付压力,一边痛下决心,用全新理念和架构重写10年存量的279万行代码,将其优化为90万行。


这就好比汽车一边高速行驶,一边“换轮胎”,难度非常大。过程中虽充满了煎熬和不被认可,但当看到一个又一个软件精英在团队涌现,交付的代码在多个维度高于华为英国安全认证中心的要求,产品及时、安全、可信地交到客户手中,我觉得一切坚持都值了。


革自己的命,义无反顾踏上架构重构之路


我们是公司传送网软件平台开发部门,类似于做手机操作系统的部门,不过我们开发的是波分、微波等网络通信产品的软件。手机操作系统让大家享受智能手机的各种功能,离不开我们开发的软件。


作为平台开发部门,我们总共支撑十余款传送产品的软件开发工作,交付压力一直比较大。时间来到2016年,产品线开始集中开发5G微波等六七个新产品,而且集中在一两年内推出来并支持测试和商用,时间紧,任务重。面对几乎翻倍的工作量,如果沿用传统的基线效率来开发,可以想象大家将一直处于疲于奔命的状态。


其实,过去我们在组织运作、工程能力等效率提升方面做了大量的努力,收效还不错,但也感觉进入了瓶颈期。原因很简单,问题的根源在我们的传统软件架构上。传统软件架构是建造软件大楼的“基座”和“框架”,已经用了十来年,随着环境的变化以及新技术、新功能特性的引入,架构难免腐化,就像一部用了很久的手机,开始变得慢、“笨重”,问题还多,再怎么修修补补都无济于事,除非做个大手术。


5G微波产品的爆发式启动开发,更将我们的开发效率问题逼上了梁山。不破不立,2016年年中,传送产品线的上级主管引进了一名海外研究所的专家,期望我们与他合作,在架构上做些探索,我作为团队新上岗的LM(Line Manager,资源线主管)承接了该工作。经过与这位专家深入讨论,发现他的业务抽象建模思想完全可以解决我们跨产品、跨芯片重用的难题。


用一个不太恰当的比喻,他的架构和我们传统架构相比,类似于“活字印刷”与“刻版印刷”之别。以往我们每支持一款新的芯片都需要重建一套软件模型,但他帮助我们构建一套统一的、可灵活拼装的通用模型,可以极大提升软硬件解耦和重用能力。用上这个架构,我们可以实现“一次开发,多次使用”,而不是之前的“使用一次,开发一次”,效率大大提高。


我们成立了一个技术项目组,花了小半年时间仔细验证,最终确认抽象模型与实际业务匹配,方向是可行的。但摆在面前的挑战非常大,需要使用新的架构方法重写原来近300万行代码。对于一个80余人的团队来说,除去正常的产品需求开发,还需要额外完成架构重构,这几乎是不可能完成的任务。


“太冒险了,万一完成不了5G微波的交付,影响太大了。”


“使用老架构,虽然效率低、问题多,勉强也能把产品推出来。”


“老架构大家都在骂,我们能不能做个软件,未来6到8年不被人骂?”


……


经过多次研讨, 大家逐渐统一了意见:研发应更关注长期,不能因为眼前的一点风险而放弃对未来的追求。但风险也不能不顾,为此,我们制定了一份详尽的计划,并且邀请了产品线3位软件牛人加入,再加上本部门五六位软件高手的投入,组成了一个10余人的小团队探路,准备杀出一条血路,革自己的命。


写最优秀的代码,不“爽”不休


架构重构就像把老房子推倒重建,代码就是高楼大厦的一砖一瓦,没有高质量的代码,任何好的架构都会演变成一个坏的架构。在重写近300万行代码之前,大家对什么是最优秀的代码进行了讨论。


写代码就像是艺术创作,优秀的原则很难形成统一标准,而软件总工程师申力华常常挂在嘴边的“爽”字,成为我们对代码的一致追求。“爽”是什么概念?现在回头来看,其实就是“Clean Code”,代码要简洁、易阅读、易重用、易扩展、易测试、高可靠。其次,大家一致认可函数要短小、文件要小,函数深度不能过深、文件不要网状依赖……


要写出“爽”的代码,第一个面临的就是编程语言的选择。C++在公司已经用了十几年,我们都清楚C++的复杂,都对C++代码中经常遇到的内存管理问题深恶痛绝。几个技术专家在工作之外,深入学习和实践了C++11,深知C++11在编码效率和安全性上具有天然的优势,而且C++11已经得到业界的认可。但C++11在华为产品中无应用经验,无支撑工具链,有人认为最好等配套工具成熟后,再切换编程语言。在没有经验和工具支撑的情况下,谁敢去脱一层皮?但最后大家还是统一了认识,不脱皮,何来脱胎换骨!编程语言应该切换成C++11,在使用中催熟工具。


为了让我们的架构约束得到落实,为了让代码简洁,我们部署了诸多代码门禁,不符合要求的“砖瓦”连“施工场地”都进入不了。我们参考优秀开源代码库的要求,制定严格的标准(如函数最大圈复杂度不能超过5,函数代码、函数行数不能超过30行),超出门禁标准的代码不允许入库。严苛的门禁对固有的编码习惯形成巨大的冲击,所有代码都需要白盒测试(注:在知道目标功能的前提下采用的一种测试方法,与黑箱测试法不同,白箱测试法关注程序在设计盒定义方面的缺陷与错误,故要求对程序代码本身要有较详尽的了解)覆盖,因此带来了成倍的编码工作量,以至代码一度堆积到上万行无法上库。一时间,团队中“认清现实、杜绝理想主义”的呼声越来越高。


我们进行了激烈的辩论,虽然对绝大多数人来说,蜕变是一个痛苦的过程,但是大家也都认可好的代码能够带来质量和效率提升的价值。因此,我们解剖了从编码到上库的所有环节,有什么问题就解决什么问题。比如支撑工具PC-Lint不支持,我们就找到替代的开源工具Clang-tidy;语言和架构难,我们通过牛人带牛人,让专家手把手教;门禁严格,我们提升门禁执行效率、本地部署门禁检查项,在同等的时间内可以多次执行门禁,在实战中逐渐改变编程习惯。


在追求极致的过程中,团队成员互相检视,时刻切磋,不留情面地驳回一切不“爽”的代码。部门一名骨干成员兴冲冲地加入到该重构项目,由于是公认的软件高手,他第一次信心满满地提交了代码,但被评审人员无情地驳回了:“你这个设计不够简洁,还需要考虑异步场景的扩展性。”通过不断修改、提交,一共被驳回了8次。在开始的几次被驳回时,他虽然内心非常不服气,但经过讨论和深挖,发现确实可以找到更好的设计,最终将原来需要500行代码实现的功能现在使用200行即可实现。团队屡“驳”屡战,不“爽”不休,每一处代码的设计与编码只要觉得还可以更好,就持续优化,直至无可挑剔。新技术的引入,更好看的代码,高手间切磋带来的快感,让大家又找回了编程的乐趣。


一群软件专家在自己的“独立王国”中,恰同学少年,挥斥方遒。 


进度与质量重压下的选择


技术问题虽得到解决,然而更大的压力来自外部。交付过程中进行软件架构优化无异于飞行途中换引擎,速度必然受到影响。架构优化的优势要两三年才能凸显出来,当下感知没有那么明显,还因为人力限制等因素,给人感觉“你飞得更慢了”,质疑声不断。


内部研发过程中因为进度的延迟,多次受到产品线的投诉。产品线不断地发出预警邮件、不断地在各级会议通报风险,产品部和我们团队都承受着巨大的压力。


2017年年底,我们迎来了最艰难的时刻。5G微波正式进入预商用阶段,距离某大T运营商客户测试仅有三个月,我们还有几万行代码没写出来。产品线判断按时完成任务的风险巨大,投诉接踵而至。按照以前的方法,面对一个有进度压力的需求,复制一个代码,稍作修改即提交是最方便快捷的,虽然这种方式可能在后期问题会比较多,但不会出现大面积延迟交付的情况。


但当时我们的架构已经发生了天翻地覆的变化,要求和标准都有了更高的基线,开发进度受限。是坚持对代码的追求,还是降低标准以满足眼前的交付进度?


团队内部一直有两种不同声音,每隔半个月,双方就“房间具体要装修到什么程度”进行讨论博弈。“保守派”认为,大堂搞豪华点就行了,其他的简单装修,这样可以快速交付,面对产品线的压力小一些;“激进派”坚持高标准,所有房间的装修必须用最好的方案、最好的材料, 要做良心工程。从我的角度来说,对代码最高的要求是我们的初心,必须坚守,质量差的材料也可以完成房屋装修,但寿命不长,还时常漏水漏电、墙皮脱落,我们宁愿暂时苦一点,也要保证长期不出问题。


面对外部压力,我们也不是一个人在战斗,时任产品部部长王春钿、流程负责人杨曦给大家尽可能争取更宽松的外部环境,并争取到产品线管理层的支持,不断给大家释放压力。同时,我们预定多个会议室封闭开发,大家把手机统一放在“停机坪”上,全身心投入。那段时间大家一个星期不回家是很正常的事情,累了困了就在公司打地铺。


坚持高质量代码交付,让我们实现了以质量换进度。以前还是老架构时,写代码时间短,可能两个月就写完了,但后续问题多,解决问题也要一个半月,而且再扩展新功能很麻烦,投入大;如今虽然前期写代码要两个半月,但后续问题少,解决问题只要半个月,扩展新功能很容易、投入小。


经过一段时间的紧张开发,某大T运营商客户测试的几万行代码也按时交付了,而且质量比之前更高。


从量变到质变,奇迹发生了


就在我们没日没夜开发时,内部测试发现了某芯片存有一个致命的设计问题,可能需要改片。面临数百万美元的改片费用,产品线认为芯片早期验证存在疏漏。一纸通报批评落到了我头上,整个团队笼罩在不被信任、压力无处诉说的阴霾之中。当所有人认为只有改片这条路时,我们没有放弃。几名专家通过连续一周的论证,找到了一条可以用软件来解决芯片缺陷的方案。再经过一周的编码与验证工作,在某天的凌晨三点,验证项全部通过,大家一片欢呼,喜极而泣,不仅因为节省了数百万美元,更是因为我们通过智慧,解决了一个原以为不可能解决的问题。


这个致命问题的解决,只是我们这两年来遇到的众多问题中的一个,类似的挑战和压力无处不在。新架构、新技术与现有人员能力的不匹配带来的挫败感,产品线的不断投诉和质疑带来的无助感,有时让大家产生动摇。有一天,一个关系要好的PL(Project Leader,项目主管)骨干向我提交了辞职信,正焦头烂额的我犹如当头一棒。他说,我很清楚事情的价值,但实在太辛苦了,还不被认可。静下心来,我和他掏心掏肺地聊了很久,他理解当下兄弟们的难,现在正是缺人之际,答应等过了这段时间再走。


那段时间对我来说,压力非常大,绩效受到影响,连续两年拿了B,要好的朋友都劝我换个地方,但我还是想把事情做完,虽然不被理解,也无处诉说。有个周五晚上部门组织看电影,当天刚被产品线投诉,我心情非常压抑,电影很欢快,欢笑声此起彼伏,但我完全没看进去,坐在昏暗的影院里,一个三十多岁的大男人,眼泪止不住地流下来。


中途走出影院,外面下着淅淅沥沥的小雨,我拦了辆出租车准备回家,但想到公司肯定还有同事在加班,还有很多问题需要解决,毅然让司机调头回到公司。使命还未完成,我们还须坚持。


项目进行到中后期时,部门60%的人员都加入到了新架构重构工作中来。随着开发活动的深入,大家的能力也逐步得到提升,从量变到质变,奇迹就此发生。大家突然发现,门禁失败次数、被Committer(代码提交者)驳回的MR(提交请求)个数越来越少;白盒测试覆盖率日渐提升,迭代期间缺陷密度远低于历史水平;代码直观漂亮,书写行云流水。


新架构、新代码带来的好处终于开始显现。平台代码总量实现了从297万行到90万行的“瘦身”,我们的开发效率得到极大提升,开发相似的单板要修改的代码量比以往减少一半以上,更少的人力便可支撑现有业务。至此,交付逐步赶上进度,团队也迎来了5G微波产品的成功,5G微波和波分新产品高质量地通过120场次的客户测试。我们还意外发现,我们开发的新代码在代码重复度、函数圈复杂度等多个关键指标上优于华为英国安全认证中心的要求。


拨开云雾见月明,软件“场”已经形成


两年多来,随着一群有追求的同事敲出一行行优秀的代码,团队形成了一种软件“场”。大家已经形成一种共识,“我不愿意成为破坏软件架构和好代码的第一人”。当时跟我提离职的PL最终也留了下来,我们清楚地知道,所做之事,值得一生付出。


如今公司越来越重视软件工程能力提升,计划用5年时间,在ICT基础设施领域实现为客户打造可信的高质量产品的目标。今年年初,公司总裁任正非在《全面提升软件工程能力与实践,打造可信的高质量产品——致全体员工的一封信》中提到,“我们要从最基础的编码质量做起,视高质量代码为尊严和个人声誉”,对此我感触良多。


高质量代码就是我们心中的信仰。迎着朝阳前进,做最好的软件,我们一直在路上。希望每个人都有勇气做正确的事,有决绝的信念坚持到底,用代码筑起心中的殿堂。


-END-


推荐阅读

【01】感触极深!二十年的编程,教会我的五件事!【02】C语言、嵌入式位操作精华技巧大汇总【03】编程,它到底难在哪里?【04】为什么大量的if else这么不受待见?怎么“干掉”它?【05】每个工程师都应该了解的一些 C++ 特性


免责声明:整理文章为传播相关技术,版权归原作者所有,如有侵权,请联系删除

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存